home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / pdftops / xpdf / c++ / XRef < prev   
Text File  |  1996-06-08  |  6KB  |  258 lines

  1. //========================================================================
  2. //
  3. // XRef.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. //#pragma implementation
  11. #endif
  12.  
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "gmem.h"
  18. #include "Object.h"
  19. #include "Stream.h"
  20. #include "Lexer.h"
  21. #include "Parser.h"
  22. #include "Dict.h"
  23. #include "Error.h"
  24. #include "XRef.h"
  25.  
  26. //------------------------------------------------------------------------
  27.  
  28. #define xrefSearchSize 1024    // read this many bytes at end of file
  29.                 //   to look for 'startxref'
  30.  
  31. //------------------------------------------------------------------------
  32. // The global xref table
  33. //------------------------------------------------------------------------
  34.  
  35. XRef *xref = NULL;
  36.  
  37. //------------------------------------------------------------------------
  38. // XRef
  39. //------------------------------------------------------------------------
  40.  
  41. XRef::XRef(FileStream *str) {
  42.   int pos;
  43.   int i;
  44.  
  45.   ok = gTrue;
  46.   entries = NULL;
  47.   encrypted = gFalse;
  48.   file = str->getFile();
  49.   start = str->getStart();
  50.   pos = readTrailer(str);
  51.   if (pos == 0) {
  52.     ok = gFalse;
  53.     return;
  54.   }
  55.   entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry));
  56.   for (i = 0; i < size; ++i)
  57.     entries[i].offset = -1;
  58.   while (readXRef(str, &pos)) ;
  59. }
  60.  
  61. XRef::~XRef() {
  62.   gfree(entries);
  63. }
  64.  
  65. // Read startxref position, xref table size, and root.  Returns
  66. // first xref position.
  67. int XRef::readTrailer(FileStream *str) {
  68.   Parser *parser;
  69.   Object obj, obj2;
  70.   Dict *dict;
  71.   char buf[xrefSearchSize+1];
  72.   int pos;
  73.   char *p;
  74.   int i;
  75.  
  76.   // read last xrefSearchSize bytes
  77.   str->setPos(-xrefSearchSize);
  78.   for (i = 0; i < xrefSearchSize; ++i)
  79.     buf[i] = str->getChar();
  80.   buf[xrefSearchSize] = '\0';
  81.  
  82.   // find startxref
  83.   for (i = xrefSearchSize - 9; i >= 0; --i) {
  84.     if (!strncmp(&buf[i], "startxref", 9))
  85.       break;
  86.   }
  87.   if (i < 0)
  88.     return 0;
  89.   for (p = &buf[i+9]; isspace(*p); ++p) ;
  90.   pos = atoi(p);
  91.  
  92.   // read trailer dict
  93.   for (--i; i >= 0; --i) {
  94.     if (!strncmp(&buf[i], "trailer", 7))
  95.       break;
  96.   }
  97.   obj.initNull();
  98.   parser = new Parser(new Lexer(
  99.     new FileStream(file, str->getPos() - xrefSearchSize + i + 8, -1, &obj)));
  100.   parser->getObj(&obj);
  101.   if (obj.isDict()) {
  102.     dict = obj.getDict();
  103.     dict->lookup("Size", &obj2);
  104.     if (obj2.isInt())
  105.       size = obj2.getInt();
  106.     else
  107.       pos = 0;
  108.     obj2.free();
  109.     dict->lookup("Root", &obj2);
  110.     if (obj2.isRef()) {
  111.       rootNum = obj2.getRefNum();
  112.       rootGen = obj2.getRefGen();
  113.     } else {
  114.       pos = 0;
  115.     }
  116.     obj2.free();
  117.     dict->lookup("Encrypt", &obj2);
  118.     encrypted = !obj2.isNull();
  119.     obj2.free();
  120.   } else {
  121.     pos = 0;
  122.   }
  123.   obj.free();
  124.   delete parser;
  125.  
  126.   // return first xref position
  127.   return pos;
  128. }
  129.  
  130. // Read an xref table and the prev pointer from the trailer.
  131. GBool XRef::readXRef(FileStream *str, int *pos) {
  132.   Parser *parser;
  133.   Object obj, obj2;
  134.   int first, n, i;
  135.   GBool more;
  136.  
  137.   // make a parser
  138.   obj.initNull();
  139.   parser = new Parser(new Lexer(
  140.     new FileStream(file, start + *pos, -1, &obj)));
  141.  
  142.   // make sure it's an xref table
  143.   parser->getObj(&obj);
  144.   if (!obj.isCmd("xref"))
  145.     goto err;
  146.   obj.free();
  147.  
  148.   // read xref
  149.   parser->getObj(&obj);
  150.   while (!obj.isCmd("trailer")) {
  151.     if (!obj.isInt())
  152.       goto err;
  153.     first = obj.getInt();
  154.     obj.free();
  155.     parser->getObj(&obj);
  156.     if (!obj.isInt())
  157.       goto err;
  158.     n = obj.getInt();
  159.     obj.free();
  160.     for (i = first; i < first + n; ++i) {
  161.       if (entries[i].offset < 0) {
  162.     parser->getObj(&obj);
  163.     if (!obj.isInt())
  164.       goto err;
  165.     entries[i].offset = obj.getInt();
  166.     obj.free();
  167.     parser->getObj(&obj);
  168.     if (!obj.isInt())
  169.       goto err;
  170.     entries[i].gen = obj.getInt();
  171.     obj.free();
  172.     parser->getObj(&obj);
  173.     if (obj.isCmd("n"))
  174.       entries[i].used = gTrue;
  175.     else if (obj.isCmd("f"))
  176.       entries[i].used = gFalse;
  177.     else
  178.       goto err;
  179.     obj.free();
  180.       } else {
  181.     parser->getObj(&obj);
  182.     obj.free();
  183.     parser->getObj(&obj);
  184.     obj.free();
  185.     parser->getObj(&obj);
  186.     obj.free();
  187.       }
  188.     }
  189.     parser->getObj(&obj);
  190.   }
  191.   obj.free();
  192.  
  193.   // read prev pointer
  194.   parser->getObj(&obj);
  195.   if (!obj.isDict())
  196.     goto err;
  197.   obj.getDict()->lookup("Prev", &obj2);
  198.   if (obj2.isInt()) {
  199.     *pos = obj2.getInt();
  200.     more = gTrue;
  201.   } else {
  202.     more = gFalse;
  203.   }
  204.   obj.free();
  205.   obj2.free();
  206.  
  207.   delete parser;
  208.   return more;
  209.  
  210.  err:
  211.   ok = gFalse;
  212.   obj.free();
  213.   delete parser;
  214.   return gFalse;
  215. }
  216.  
  217. GBool XRef::checkEncrypted() {
  218.   if (encrypted) {
  219.     error(0, "PDF file is encrypted and cannot be displayed");
  220.     error(0, "*    Please send email to devsup-person@adobe.com and ask");
  221.     error(0, "*    them to prove that PDF is truly an open standard by");
  222.     error(0, "*    releasing the decryption specs to developers.  Also,");
  223.     error(0, "*    please send email to the person responsible for this");
  224.     error(0, "*    file (webmaster@... might be a good place) and ask");
  225.     error(0, "*    them to stop using encrypted PDF files.");
  226.   }
  227.   return encrypted;
  228. }
  229.  
  230. Object *XRef::fetch(int num, int gen, Object *obj) {
  231.   XRefEntry *e;
  232.   Parser *parser;
  233.   Object obj1, obj2, obj3;
  234.  
  235.   e = &entries[num];
  236.   if (e->gen == gen && e->offset >= 0) {
  237.     obj1.initNull();
  238.     parser = new Parser(new Lexer(
  239.       new FileStream(file, start + e->offset, -1, &obj1)));
  240.     parser->getObj(&obj1);
  241.     parser->getObj(&obj2);
  242.     parser->getObj(&obj3);
  243.     if (obj1.isInt() && obj1.getInt() == num &&
  244.     obj2.isInt() && obj2.getInt() == gen &&
  245.     obj3.isCmd("obj"))
  246.       parser->getObj(obj);
  247.     else
  248.       obj->initNull();
  249.     obj1.free();
  250.     obj2.free();
  251.     obj3.free();
  252.     delete parser;
  253.   } else {
  254.     obj->initNull();
  255.   }
  256.   return obj;
  257. }
  258.